package robot

import (
	"fmt"
	"gamesdk/inter"
	"runtime"
	"gamesdk/wanyu/server/api/gameapi/gameframe"
	"gamesdk/wanyu/server/api/gameapi/games/ddz/common"
	"gamesdk/wanyu/server/api/gameapi/games/ddz/game"
	"gamesdk/wanyu/server/api/gameapi/games/ddz/logic"
	"gamesdk/wanyu/server/protogo/gameddz"
	"gamesdk/wanyu/server/engine/utils"
	errors "gamesdk/wanyu/server/engine/wperror"
	wplog "gamesdk/wanyu/server/engine/wplog"
	"github.com/golang/protobuf/proto"
	b3 "github.com/magicsea/behavior3go"
	b3core "github.com/magicsea/behavior3go/core"
)

//出牌数据
type outData struct {
	//当前出牌回合, 从0开始递增
	round int32
	//玩家当前回合出牌类型
	option gameddz.OptionType
	//玩家当前回合出牌数据
	cards []logic.Card
}

type robot struct {
	//机器人管理
	mgr wanju_gameframe.RobotMgr
	//游戏配置
	gameCfg *common.GameCfg
	//机器人id
	robotID string
	//机器人玩家实例
	robotPlayer wanju_gameframe.Player
	//机器人座位号
	mySeat int32
	//机器人定时器
	timerID int
	//游戏步骤
	gameStep gameddz.GameStep
	//庄家座位号
	bankerSeat int32
	//当前操作玩家座位号
	currentSeat int32
	//当前最大叫地主倍数（不叫，1分，2分，3分）
	//maxcalltype gameddz.CallBankerType
	//机器人手牌
	handCards []logic.Card
	//机器人手牌拆分组合
	cardGroups []*logic.CardGroup
	//所有玩家手牌数量
	handCardsCount []int32
	//所有玩家最新出牌情况，是否已经pass
	isPassCard []bool
	//当前回合第一个出牌玩家
	firstOutSeat int32
	//当前回合最大出牌玩家
	maxOutSeat int32
	//当前回合最大出牌牌组
	maxOutCards []logic.Card
	//地主3张牌
	threeCards []logic.Card
	//记牌器, 记录出牌以及自己手牌之外剩下的牌
	leftCards []logic.Card

	// there is too fucking much place where leftCards was assigned
	// so update left cards most value group in export data update, this should be ok
	leftCardGroups []*logic.CardGroup
	standCard *logic.Card
	//当前出牌回合数
	round int32
	//所有玩家的出牌记录
	outCards [][]*outData

	//行为树指针，房间持有，保证线程安全
	tree *b3core.BehaviorTree
	//导出给行为树的数据
	exportData *ExportData
	lastOutCardType []logic.CardsType
	lastPassCardType []logic.CardsType
}

func (rb *robot) getCardsByGroup(t logic.CardsType) []logic.CardGroup {
	res := make([]logic.CardGroup, 0)
	for _, g := range rb.cardGroups {
		if g.Type == t {
			res = append(res, *g)
		}
	}
	return res
}
func (rb *robot) getCardCount(n logic.CardPoint) int {
	res := 0
	for _, g := range rb.handCards {
		if g.Number == int(n) {
			res++
		}
	}
	return res
}
func (rb *robot) getCard(n logic.CardPoint) []logic.Card {
	res := make([]logic.Card, 0)
	for _, g := range rb.handCards {
		if g.Number == int(n) {
			res = append(res, g)
		}
	}
	return res
}
//CreateRobot 创建机器人实例
func CreateRobot(m inter.RobotInter, player inter.UserInetr, tree *b3core.BehaviorTree, rCfg *wanju_gameframe.RobotCfg) wanju_gameframe.Robot {
	if nil == player {
		return &robot{exportData: &ExportData{}}
	}
	var pRobot = &robot{
	//	mgr:            m,
		gameCfg:        &common.GameCfg{GameCfg: rCfg.GameCfg, KindCfg: rCfg.KindCfg, ExGameCfg: rCfg.ExGameCfg.(*gameddz.GameExCfg), ExKindCfg: rCfg.ExKindCfg.(*gameddz.KindExCfg)},
		timerID:        -1,
	//	robotID:        player.GetAttri().PlayerID,
	//	robotPlayer:    player,
	//	mySeat:         int32(player.GetInfo().Seat),
		gameStep:       gameddz.GameStep_ST_WAITING_START,
		bankerSeat:     -1,
		currentSeat:    -1,
		handCards:      nil,
		cardGroups:     nil,
		handCardsCount: make([]int32, rCfg.GameCfg.MaxPlayerCnt),
		isPassCard:     make([]bool, rCfg.GameCfg.MaxPlayerCnt),
		firstOutSeat:   -1,
		maxOutSeat:     -1,
		maxOutCards:    nil,
		threeCards:     nil,
		leftCards:      nil,
		round:          0,
		outCards:       make([][]*outData, rCfg.GameCfg.MaxPlayerCnt),
		lastOutCardType: make([]logic.CardsType, 3),
		lastPassCardType: make([]logic.CardsType, 3),
		tree:           tree,
		exportData:     &ExportData{},
	}
	pRobot.gameCfg.GameStartAni = 1000
	pRobot.gameCfg.SendCardAni = 2700
	pRobot.gameCfg.EnsureBankerAni = 700
	pRobot.gameCfg.WaitEndAni = 2000
	pRobot.gameCfg.GameEndAni = 3000
	return pRobot
}

//来自游戏框架层的消息
func (rb *robot) OnFrameMsg(eventType int32, event proto.Message) {
	//这里不用处理框架层的消息，所有事件从DealEvent处理
}

//处理具体游戏事件
func (rb *robot) OnGameEvent(eventType int32, event proto.Message) {
	var evType = gameddz.Event(eventType)
	switch evType {
	case gameddz.Event_PLAY_INFO:
	case gameddz.Event_TABLE_INFO:
		bnewstep := rb.processTableInfo(event.(*gameddz.TableInfo))
		//刚进入某一阶段
		if bnewstep && (rb.gameStep == gameddz.GameStep_ST_PLAYER_DOUBLE || rb.gameStep == gameddz.GameStep_ST_ROB_BANKER) {
			rb.checkRunTree()
		}
	case gameddz.Event_GAME_START:
		rb.processGameStart(event.(*gameddz.GameStart))
	case gameddz.Event_SEND_CARD:
	case gameddz.Event_GAME_ROUNDER:
		rb.processGameRound(event.(*gameddz.GameRounder))
	case gameddz.Event_GAME_END:
		rb.processGameEnd(event.(*gameddz.GameEnd))
	case gameddz.Event_CALL_BANKER_RESP:
		rb.processCallBanker(event.(*gameddz.CallBanker))
	case gameddz.Event_ENSURE_BANKER_NOTIFY:
		rb.processEnsureBanker(event.(*gameddz.EnsureBanker))
	case gameddz.Event_PLAYER_DOUBLE_RESP:
		rb.processPlayerDouble(event.(*gameddz.PlayerDouble))
	case gameddz.Event_START_OUTCARD_NOTIFY:
		rb.processStartOutCard(true, event.(*gameddz.GameRounder))
	case gameddz.Event_OUT_CARD_RESP:
		rb.processOutCard(event.(*gameddz.OutCard))
	case gameddz.Event_OUT_CARD_NEW_ROUND:
		rb.processStartOutCard(false, event.(*gameddz.GameRounder))
	case gameddz.Event_ROB_BANKER_RESP:
		rb.processRobBanker(event.(*gameddz.RobBanker))
	default:
		//errors.CheckEx(false, cst.ErrGame, cst.ErrorParam, " eventType error ")
	}
}

//定时器，当游戏处于运行状态时，框架层会每一段时间调用一次该接口
//输入： timeId:定时器id, userData:设置定时器时传给框架层的参数
//输出：shouldContinue: 定时器是否继续，如果返回false，框架层将自动撤销该定时器
func (rb *robot) OnTimeout(timerID int, userData interface{}) (shouldContinue bool) {
	userData.(func())()
	return false
}

//获取导出给决策树的导出数据，此接口必须返回结构体的指针
func (rb *robot) GetExportData() interface{} {
	return rb.exportData
}

func (rb *robot) updateExportData() {
	rb.exportData.GameStep = int(rb.gameStep)
	rb.exportData.IsBanker = rb.bankerSeat == rb.mySeat

	if -1 == rb.bankerSeat {
		rb.exportData.IsBankerPrev = false
		rb.exportData.IsBankerNext = false
		rb.exportData.BankerCardsCount = 0
		rb.exportData.BankerPrevCardsCount = 0
		rb.exportData.BankerNextCardsCount = 0
	} else {
		bankerseat := rb.bankerSeat
		bankerprev := (bankerseat + 2) % int32(rb.gameCfg.GameCfg.MinPlayerCnt)
		bankernext := (bankerseat + 1) % int32(rb.gameCfg.GameCfg.MinPlayerCnt)
		rb.exportData.IsBankerPrev = bankerprev == rb.mySeat
		rb.exportData.IsBankerNext = bankernext == rb.mySeat
		rb.exportData.BankerCardsCount = int(rb.handCardsCount[bankerseat])
		rb.exportData.BankerPrevCardsCount = int(rb.handCardsCount[bankerprev])
		rb.exportData.BankerNextCardsCount = int(rb.handCardsCount[bankernext])
	}
	rb.exportData.HandCardsValue, rb.cardGroups = logic.GetMostValueGroup(rb.handCards)
	//这些是跟出牌有关的信息，这里做判断，避免一些计算
	if rb.gameStep == gameddz.GameStep_ST_OUT_CARD {

		rb.exportData.IsLeftOneCards = logic.GetCardsType(rb.handCards) > logic.NONE
		rb.exportData.IsCanOutAll = logic.CompareCards(rb.maxOutCards, rb.handCards)
		rb.exportData.IsFirstOut = nil == rb.maxOutCards
		if -1 == rb.bankerSeat || -1 == rb.maxOutSeat {
			rb.exportData.IsBankeOut = false
			rb.exportData.IsBankePrevOut = false
			rb.exportData.IsBankeNextOut = false
			rb.exportData.IsBankerPass = false
			rb.exportData.IsBankerPrevPass = false
			rb.exportData.IsBankerNextPass = false
		} else {
			bankerprev := (rb.bankerSeat + 2) % int32(rb.gameCfg.GameCfg.MinPlayerCnt)
			bankernext := (rb.bankerSeat + 1) % int32(rb.gameCfg.GameCfg.MinPlayerCnt)
			rb.exportData.IsBankeOut = rb.bankerSeat == rb.maxOutSeat
			rb.exportData.IsBankePrevOut = bankerprev == rb.maxOutSeat
			rb.exportData.IsBankeNextOut = bankernext == rb.maxOutSeat
			rb.exportData.IsBankerPass = rb.isPassCard[rb.bankerSeat]
			rb.exportData.IsBankerPrevPass = rb.isPassCard[bankerprev]
			rb.exportData.IsBankerNextPass = rb.isPassCard[bankernext]
		}

		outType := logic.GetCardsType(rb.maxOutCards)
		rb.exportData.IsOutSingle = outType == logic.SINGLE
		rb.exportData.IsOutDouble = outType == logic.DOUBLE
		rb.exportData.OutCardCount = len(rb.maxOutCards)
		rb.exportData.OutCardValue = logic.GetCardsValue(rb.maxOutCards)

		//自己手牌是否满足一组小牌， 其他绝对大牌的赢牌路径
		rb.exportData.IsAllBigWin = logic.IsCanAbsWin(rb.cardGroups, rb.leftCards, rb.mySeat != rb.bankerSeat)
		//自己跟牌之后是否能进入一组小牌， 其他绝对大牌的赢牌路径
		//跟牌情况下才计算
		if nil == rb.maxOutCards {
			rb.exportData.IsCanAllBig = false
		} else {
			rb.exportData.IsCanAllBig, _ = logic.GenCardCanAbsWin(rb.cardGroups, rb.handCards, rb.maxOutCards, rb.leftCards, rb.mySeat != rb.bankerSeat)
		}
	}
	//自己手牌情况
	bombcount, counts := logic.GetCardCounts(rb.handCards)
	rb.exportData.IsHasBigKing = counts[17] > 0
	rb.exportData.IsHasSmallKing = counts[16] > 0
	rb.exportData.MyPoker2Count = counts[15]
	rb.exportData.MyPoker2More = counts[15] + counts[16] + counts[17]
	rb.exportData.MyPokerACount = counts[14]
	rb.exportData.MyPokerAMore = counts[14] + counts[15] + counts[16] + counts[17]
	if counts[16] > 0 && counts[17] > 0 {
		rb.exportData.MyBombCount = bombcount + 1
	} else {
		rb.exportData.MyBombCount = bombcount
	}
	bombcountMaxValue := 0
	for _, g := range rb.cardGroups {
		if g.Type == logic.BOMB || g.Type == logic.ROCKET {
			bombcountMaxValue++
		}
	}
	rb.exportData.MyBombCountMaxValue = bombcountMaxValue
	rb.exportData.MyNoKingBombCount = bombcount
	rb.exportData.HandCardGroupNum = len(rb.cardGroups)
	_, rb.leftCardGroups = logic.GetMostValueGroup(rb.leftCards)

	maxValue := -1
	for _, g := range rb.leftCardGroups {
		if g.Type == logic.SINGLE {
			if g.Value > maxValue {
				maxValue = g.Value
				rb.standCard = &g.Cards[0]
			}
		}
	}

	var leftMaxBombValue, leftMaxSingleValue, leftMaxDoubleValue int
	for _, g := range rb.leftCardGroups {
		if g.Type == logic.BOMB {
			leftMaxBombValue = g.Value
		}
		if g.Type == logic.SINGLE {
			leftMaxSingleValue = g.Value
		}
		if g.Type == logic.DOUBLE {
			leftMaxDoubleValue = g.Value
		}
	}
	bombs := rb.getCardsByGroup(logic.BOMB)
	getMaxValueCardGroup := func(gs []logic.CardGroup) *logic.CardGroup {
		maxValue := 0
		maxIdx := -1
		for i, g := range gs {
			if g.Value > maxValue {
				maxIdx = i
				maxValue = g.Value
			}
		}
		return &gs[maxIdx]
	}
	if len(bombs) > 0 {
		maxGroup := getMaxValueCardGroup(bombs)
		rb.exportData.IsMyBombGreaterThanLeft = maxGroup.Value > leftMaxBombValue
	} else {
		rb.exportData.IsMyBombGreaterThanLeft = false
	}
	singles := rb.getCardsByGroup(logic.SINGLE)
	if len(singles) > 0 {
		rb.exportData.MySingleCardsNum = len(singles)
		maxGroup := getMaxValueCardGroup(singles)
		rb.exportData.IsMySingleGreaterThanLeft = maxGroup.Value > leftMaxSingleValue
	} else {
		rb.exportData.MySingleCardsNum = 0
	}
	doubles := rb.getCardsByGroup(logic.DOUBLE)
	if len(doubles) > 0 {
		rb.exportData.MyDoubleCardsNum = len(doubles)
		maxGroup := getMaxValueCardGroup(doubles)
		rb.exportData.IsMyDoubleGreaterThanLeft = maxGroup.Value > leftMaxDoubleValue
	} else {
		rb.exportData.MyDoubleCardsNum = 0
	}
	//其他人手牌情况
	bombcount, counts = logic.GetCardCounts(rb.leftCards)
	rb.exportData.IsOtherBigKing = counts[17] > 0
	rb.exportData.IsOtherSmallKing = counts[16] > 0
	rb.exportData.OtherPoker2Count = counts[15]
	rb.exportData.OtherPoker2More = counts[15] + counts[16] + counts[17]
	rb.exportData.OtherPokerACount = counts[14]
	rb.exportData.OtherPokerAMore = counts[14] + counts[15] + counts[16] + counts[17]
	if counts[16] > 0 && counts[17] > 0 {
		rb.exportData.OtherBombCount = bombcount + 1
	} else {
		rb.exportData.OtherBombCount = bombcount
	}

	for i := len(counts) - 1; i >= 3; i-- {
		if counts[i] >= 1 {
			rb.exportData.OtherMaxSingle = i
			break
		}
	}
	for i := len(counts) - 1; i >= 3; i-- {
		if counts[i] >= 2 {
			rb.exportData.OtherMaxDouble = i
			break
		}
	}

	if rb.gameStep == gameddz.GameStep_ST_PLAYER_DOUBLE {
		rb.exportData.MyHandCardsValue = game.GetThreeCardsHolderInstance().GetCardsValue(int(rb.mySeat))
	} else {
		rb.exportData.MyHandCardsValue = game.GetThreeCardsHolderInstance().GetCardsValue3(int(rb.mySeat))
	}
	if rb.gameStep == gameddz.GameStep_ST_PLAYER_DOUBLE || rb.gameStep == gameddz.GameStep_ST_ROB_BANKER || rb.gameStep == gameddz.GameStep_ST_CALL_BANKER {
		{
			myV := game.GetThreeCardsHolderInstance().GetCardsValue3(int(rb.mySeat)) // self with 3, others not

			a := 0
			b := 0
			other_max := 0
			if rb.mySeat == 0 {
				a = 1
				b = 2
			} else if rb.mySeat == 1 {
				a = 0
				b = 2
			} else {
				a = 0
				b = 1
			}
			av := game.GetThreeCardsHolderInstance().GetCardsValue(a)
			bv := game.GetThreeCardsHolderInstance().GetCardsValue(b)
			if av > bv {
				other_max = av
			} else {
				other_max = bv
			}
			rb.exportData.CardsValueDiffWithAnotherMax = myV - other_max
		}
		{
			myV := 0
			if rb.bankerSeat == rb.mySeat {
				rb.exportData.CardsValueDiffWithBanker = 0
			} else {
				myV = game.GetThreeCardsHolderInstance().GetCardsValue(int(rb.mySeat))
				rb.exportData.CardsValueDiffWithBanker = myV - game.GetThreeCardsHolderInstance().GetCardsValue3(int(rb.bankerSeat))
			}
		}
	}
	fmt.Println("Seat: ", rb.mySeat, " MyHandCardsValue ", rb.exportData.MyHandCardsValue, " CardsValueDiffWithAnotherMax ", rb.exportData.CardsValueDiffWithAnotherMax, " CardsValueDiffWithBanker ", rb.exportData.CardsValueDiffWithBanker)


	if -1 != rb.bankerSeat {
		bankerseat := rb.bankerSeat
		bankerprev := (bankerseat + 2) % int32(rb.gameCfg.GameCfg.MinPlayerCnt)
		bankernext := (bankerseat + 1) % int32(rb.gameCfg.GameCfg.MinPlayerCnt)

		rb.exportData.BankerLastCardType = int(rb.lastOutCardType[bankerseat])
		rb.exportData.EarlyBankerLastCardType = int(rb.lastOutCardType[bankerprev])
		rb.exportData.LateBankerLastCardType = int(rb.lastOutCardType[bankernext])
		rb.exportData.BankerPassType = int(rb.lastPassCardType[bankerseat])
		rb.exportData.EarlyBankerPassType = int(rb.lastPassCardType[bankerprev])
		rb.exportData.LateBankerPassType = int(rb.lastPassCardType[bankernext])

		_, g := logic.GetMostValueGroup(rb.handCards)
		rb.exportData.HandCardGroupTypes = rb.exportData.HandCardGroupTypes[:0]
		for _, v := range g {
			rb.exportData.HandCardGroupTypes = append(rb.exportData.HandCardGroupTypes, int(v.Type))
		}
	}

}

func (rb *robot) resetRobotInfo() {
	rb.killRobotTimer()
	rb.gameStep = gameddz.GameStep_ST_WAITING_START
	rb.bankerSeat = -1
	rb.currentSeat = -1
	rb.handCards = nil
	rb.cardGroups = nil
	rb.handCardsCount = make([]int32, rb.gameCfg.GameCfg.MaxPlayerCnt)
	rb.isPassCard = make([]bool, rb.gameCfg.GameCfg.MaxPlayerCnt)
	rb.firstOutSeat = -1
	rb.maxOutSeat = -1
	rb.maxOutCards = nil
	rb.threeCards = nil
	rb.leftCards = nil
	rb.round = 0
	rb.outCards = make([][]*outData, rb.gameCfg.GameCfg.MaxPlayerCnt)
	rb.lastPassCardType = make([]logic.CardsType, 3)
	rb.lastOutCardType = make([]logic.CardsType, 3)
	rb.exportData = &ExportData{}
}

func (rb *robot) killRobotTimer() {
	rb.mgr.RemoveTimer(rb.timerID)
}

func (rb *robot) setRobotTimer(ms int, f func()) {
	rb.killRobotTimer()
	rb.timerID = rb.mgr.OnceTimer(wanju_gameframe.UserData{Obj: rb, UserData: f}, ms)
}

func (rb *robot) checkRunTree() {
	rb.killRobotTimer()
	//每个游戏阶段，不同处理
	switch rb.gameStep {
	case gameddz.GameStep_ST_CALL_BANKER:
		if rb.currentSeat != rb.mySeat {
			return
		}
	case gameddz.GameStep_ST_PLAYER_DOUBLE:
		{}
	case gameddz.GameStep_ST_OUT_CARD:
		if rb.currentSeat != rb.mySeat {
			return
		}
		if rb.maxOutCards == nil {
			//主动出牌且手上只剩一张牌
			if len(rb.handCards) == 1 {
				rb.sendOutCardmsgEx(utils.RandIntRange(300, 600), gameddz.OptionType_OP_OUT_CARD, []logic.Card{rb.handCards[0]})
				return
			}
		} else {
			//被动出牌
			if logic.ROCKET == logic.GetCardsType(rb.maxOutCards) {
				rb.doPassCardQuick(utils.RandIntRange(300, 600))
				return
			} else if isCanOut, _ := logic.SearchLargerCardType(rb.maxOutCards, rb.handCards, true); !isCanOut {
				rb.doPassCard()
				return
			}
		}
	case gameddz.GameStep_ST_ROB_BANKER:
		if rb.currentSeat != rb.mySeat {
			return
		}
	default:
		return
	}
	//begin := time.Now()
	//wplog.Debugf(rb.robotPlayer.GetDLogPrefix()+"机器人手牌 --- before : %v ", rb.handCards)
	//更新导出数据
	rb.updateExportData()
	//wplog.Debugf(rb.robotPlayer.GetDLogPrefix()+"机器人手牌 --- after : %v ", rb.handCards)
	//wplog.Debugf(rb.robotPlayer.GetDLogPrefix()+"花费时间 --- before : %v ms", time.Since(begin).Milliseconds())
	//wplog.Debugf(rb.robotPlayer.GetDLogPrefix()+"机器人牌值: %d", rb.exportData.HandCardsValue)
	//wplog.Debugf(rb.robotPlayer.GetDLogPrefix()+"机器人 exportData: %+v", *rb.exportData)
	//for index, group := range rb.cardGroups {
	//	wplog.Debugf(rb.robotPlayer.GetDLogPrefix()+" checkRunTree --- index : %d, %v", index, *group)
	//}
	//开始执行行为树
	rb.startRunTree()
	//wplog.Debugf(rb.robotPlayer.GetDLogPrefix()+"花费时间 --- after : %v ms", time.Since(begin).Milliseconds())
}

func (rb *robot) startRunTree() {
	defer func() {
		if r := recover(); r != nil {
			err := r.(error)
			wplog.Error(err)
			buf := make([]byte, 2048)
			length := runtime.Stack(buf, false)
			wplog.Error(string(buf[:length]))
		}
	}()

	errors.Check(nil != rb.tree, errors.ErrorGameCfg, "tree is nil !!!")
	if nil != rb.tree {
		//输入板
		board := b3core.NewBlackboard()
		state := rb.tree.Tick(rb, board)
		errors.Check(state == b3.SUCCESS, errors.ErrorGameCfg, "behavior tree tick failed !!!")
	}
}

//判断机器人能否安全出此牌型
func (rb *robot) isCanSafeOutCards(cards []logic.Card, isCompare bool) bool {
	length := int32(len(cards))
	prevseat := (rb.mySeat + 2) % 3
	nextseat := (rb.mySeat + 1) % 3
	otherct1 := rb.handCardsCount[prevseat]
	otherct2 := rb.handCardsCount[nextseat]
	var ret = (otherct1 != length && otherct2 != length)
	if ret || !isCompare {
		return ret
	}
	if exist, _ := logic.SearchLargerCardType(cards, rb.leftCards, false); !exist {
		ret = true
	}
	return ret
}

//敌人,同伴 是否报单, 报双
func (rb *robot) isPlayerAlarm(isPartner bool, count int32) bool {
	prevseat := (rb.bankerSeat + 2) % 3
	nextseat := (rb.bankerSeat + 1) % 3
	if isPartner {
		switch rb.mySeat {
		case rb.bankerSeat:
			return false
		case prevseat:
			return rb.handCardsCount[nextseat] == count
		case nextseat:
			return rb.handCardsCount[prevseat] == count
		}
	}
	if rb.mySeat == rb.bankerSeat {
		return (rb.handCardsCount[prevseat] == count || rb.handCardsCount[nextseat] == count)
	}
	return rb.handCardsCount[rb.bankerSeat] == count
}

//是否是对手，true对手，false队友
func (rb *robot) isOpponent(seat int32) bool {
	if rb.mySeat == seat || rb.mySeat == rb.bankerSeat || seat == rb.bankerSeat {
		return false
	}
	return true
}

//某个玩家是否不能大过此出牌
func (rb *robot) isPlayerNotOut(seat int32, isAbs bool) bool {
	outs := rb.maxOutCards
	if !isAbs && rb.handCardsCount[seat] < int32(len(outs)) {
		return true
	}
	var cards []logic.Card
	if rb.mySeat == seat {
		cards = rb.handCards
	} else {
		cards = rb.leftCards
	}
	if exist, _ := logic.SearchLargerCardType(outs, cards, isAbs); !exist {
		return true
	}
	return false
}

func (rb *robot) doOut(groupType int) bool {
	out := make([]logic.Card, 0)
	ct := logic.CardsType(groupType)
	_, gg := logic.GetMostValueGroup(rb.handCards)
	switch ct {
	case logic.THREEANDSINGLE:
		for _, g := range gg {
			if g.Type == logic.THREE || g.Type == logic.SINGLE {
				out = append(out, g.Cards...)
			}
		}
		if len(out) != 4 {
			out = out[:0]
			var part3 []logic.Card
			var part2 []logic.Card
			singles := make([]logic.Card, 0)
			for _, g := range gg {
				if g.Type == logic.THREEANDDOUBLE {
					if g.Cards[0].Number == g.Cards[1].Number && g.Cards[1].Number == g.Cards[2].Number {
						part3 = g.Cards[:3]
						part2 = g.Cards[3:]
					} else {
						part3 = g.Cards[2:]
						part2 = g.Cards[:2]
					}
				}
				if g.Type == logic.SINGLE {
					singles = append(singles, g.Cards...)
				}
			}
			out = part3 // GetMostValueGroup returned is copied data, so it is ok
			if len(singles) == 0 {
				out = append(out, part2[0])
			} else {
				out = append(out, singles[0])
			}
		}
	case logic.AIRPLANEANDSINGLE:   // AIRPLANEANDDOUBLE ---> AIRPLANEANDSINGLE
		var jet1 []logic.Card
		singles := make([]logic.Card, 0)
		for _, g := range gg {
			if g.Type == logic.AIRPLANEANDDOUBLE {
				jet1 = make([]logic.Card, len(g.Cards))
				copy(jet1, g.Cards)
			}
			if g.Type == logic.SINGLE {
				singles = append(singles, g.Cards...)
			}
		}
		if len(jet1) > 0 && len(singles) > 1 {
			jet1 = logic.Sort111(jet1, logic.AIRPLANEANDDOUBLE)
			doubleN := len(jet1) / 5
			doubleParts := jet1[len(jet1)-doubleN*2:]
			tripleParts := jet1[:doubleN*3]
			out = append(out, tripleParts...)
			if len(singles) >= doubleN {
				out = append(out, singles[:doubleN]...)
			} else {
				out = append(out, singles...)
				doubleParts = doubleParts[:len(singles)*2]
				out = append(out, doubleParts...)
			}
		}
	}
	fmt.Println("aaaa", out, " ", groupType)
	rb.sendOutCardmsg(gameddz.OptionType_OP_OUT_CARD, out)
	return true
}
